from random import randint

from django.shortcuts import render, redirect
from django.views import View
from django import http
import re
from django.contrib.auth import login, logout,authenticate
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

from celery_tasks.sms import tasks
from meiduo_mall.utils.response_code import RETCODE
from django_redis import get_redis_connection
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from meiduo_mall.utils.views import LoginRequiredView
import json
from django.core.mail import send_mail
from django.db import DatabaseError

from .models import User, Address
from celery_tasks.email.tasks import send_verify_email
from .utils import get_user_check_token,generate_verify_email_url
import logging
from goods.models import SKU
from carts.utils import merge_cart_cookie_to_redis
from .utils import get_user_by_account


logger = logging.getLogger()

# Create your views here.

class RegisterView(View):


    def get(self, request):
        return render(request, 'register.html')

    def post(self, request):

        query_dict = request.POST
        username = query_dict.get('username')
        password = query_dict.get('password')
        password2 = query_dict.get('password2')
        mobile = query_dict.get('mobile')
        sms_code = query_dict.get('sms_code')
        allow = query_dict.get('allow')

        if all([username, password, password2, mobile, sms_code, allow]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20个的密码')
        if password != password2:
            return http.HttpResponseForbidden('输入两次密码不一致')
        if not re.match(r'^1[[345789]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号')

        redis_conn = get_redis_connection('verify_codes')
        sms_code_server_bytes = redis_conn.get('sms_%s' % mobile)

        if sms_code_server_bytes is None:
            return http.JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '短信验证码已过期'})

        redis_conn.delete('sms_%s' % mobile)

        sms_code_server = sms_code_server_bytes.decode()
        if sms_code != sms_code_server:
            return http.JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '短信验证码填写错误'})

        # user = User.objects.create(
        #     username = username,
        #     password = password
        # )
        # user.set_password(password)
        # user.save()

        user = User.objects.create_user(username=username, password=password, mobile=mobile)

        # request.session['id'] = user.id
        # user_id = request.session['id']
        login(request, user)
        response = redirect('/')
        response.set_cookie('username', user.username, max_age= settings.SESSION_COOKIE_AGE)

        # return http.HttpResponse('注册成功,应该去到首页!')
        return response

class UsernameCountView(View):

    def get(self, request, username):

        count = User.objects.filter(username=username).count()

        data = {
            'count': count,
            'code':RETCODE.OK,
            'errmsg':'OK'
        }

        return http.JsonResponse(data)

class MobileCountView(View):

    def get(self, request, mobile):

        count = User.objects.filter(mobile=mobile).count()

        data = {
            'count': count,
            'code':RETCODE.OK,
            'errmsg':'OK'
        }

        return http.JsonResponse(data)


class LoginView(View):

    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):

        # 接收表单数据
        query_dict = request.POST
        print(query_dict.dict().keys())
        username = query_dict.get('username')
        password = query_dict.get('password')
        remembered = query_dict.get('remembered')

        # 校验
        if all([username, password]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        # 登陆验证
        user = authenticate(request, username=username, password=password)
        # if 如果是手机号登陆:
        #     user = User.objects.get(mobile=username)
        # elif 如果是邮箱登陆:
        #     user = User.objects.get(email=username)
        # else:
        #     user = User.objects.get(username=username)

        # user = User.objects.get(email=username)
        # user.check_password(password)

        # 判断用户是否通过身份认证
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或者密码错误'})

        # 状态保持
        login(request, user)
        # if remembered is None:
        #     request.session.set_expiry(0)
        # else:
        #     request.session.set_expiry(3600 * 24 * 7)

        # request.session.set_expiry(0 if remembered is None else (3600 * 24 * 7))
        request.session.set_expiry(None if remembered else 0)

        next = request.GET.get('next')
        response = redirect(next or '/')
        # response.set_cookie('username', user.username, max_age=None if remembered is None else settings.SESSION_COOKIE_AGE)
        response.set_cookie('username', user.username, max_age=remembered and settings.SESSION_COOKIE_AGE)

        # 重定向到首页
        # return http.HttpResponse('登陆成功，跳转到首页界面')
        
        merge_cart_cookie_to_redis(request, response)

        return response

class LogoutView(View):

    def get(self, request):

        logout(request)

        response = redirect('users:login')
        response.delete_cookie('username')

        return response

# class InfoView(View):
#
#     def get(self, request):
#         user = request.user
#         if user.is_authenticated:
#             return render(request, 'user_center_info.html')
#         else:
#             return redirect('/login/?next=/info/')

class InfoView(LoginRequiredMixin, View):

    def get(self, request):

        return render(request, 'user_center_info.html')

# @method_decorator(login_required, name='get')
# class InfoView(LoginRequiredMixin, View):
#
#     def get(self, request):
#         return render(request, 'user_center_info.html')

class EmailView(LoginRequiredView):

    def put(self, request):
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseForbidden('邮箱格式有误')

        user = request.user
        if user.email != email:
            user.email = email
            user.save()

        # html_message = '<p>这是一个激活邮件<a href="http://www.baidu.com">点我一下<a></p>'
        # send_mail(subject='激活邮箱', message='普通文本', from_email='美多商城<itcast99@163.com>', recipient_list=[email],html_message=html_message)

        # verify_url = 'http://www.baidu.com'
        verify_url = generate_verify_email_url(user)
        send_verify_email.delay(email, verify_url)

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})

class EmailVerifyView(View):

    def get(self, request):
        token = request.GET.get('token')

        user = get_user_check_token(token)

        if user is None:
            return http.HttpResponseForbidden('邮箱激活失败')

        user.email_active = True
        user.save()

        return render(request, 'user_center_info.html')


class AddressesView(LoginRequiredView):

    def get(self, request):

        user = request.user
        address_qs = Address.objects.filter(user = user, is_deleted=False)
        # user.addresses.filter(is_deleted = False)
        address_list = []
        for address in address_qs:
            address_list.append({
                'id': address.id,
                'title': address.title,
                'receiver': address.receiver,
                'province_id': address.province_id,
                'province': address.province.name,
                'city_id': address.city_id,
                'city': address.city.name,
                'district_id': address.district_id,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email
            })

        content = {
            'addresses': address_list,
            'default_address_id': user.default_address_id
        }

        return render(request, 'user_center_site.html', content)


class AddressCreateView(LoginRequiredView):

    def post(self, request):
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        if all([title, receiver, province_id, city_id, district_id, place, mobile]) is False:
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('手机号格式有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')

        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')


        user = request.user
        try:
            address = Address.objects.create(
                user=user,
                title=title,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except DatabaseError as e:
            logger.error(e)
            return http.HttpResponseForbidden('新增收获地址有误')

        if user.default_address is None:
            user.default_address = address
            # user.default_address_id = address.id
            user.save()

        address_dict = {
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province_id': address.province_id,
            'province': address.province.name,
            'city_id': address.city_id,
            'city': address.city.name,
            'district_id': address.district_id,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增收货地址成功', 'address': address_dict})


class UpdateDestroyAddressView(LoginRequiredView):

    def put(self, request, address_id):

        user = request.user
        try:
            address = Address.objects.get(id=address_id, user=user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('address_id有误')

        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        if all([title, receiver, province_id, city_id, district_id, place, mobile]) is False:
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('手机号格式有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')

        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')

        # try:
        #     address = Address.objects.create(
        #         user=user,
        #         title=title,
        #         receiver=receive,
        #         province_id=province_id,
        #         city_id=city_id,
        #         district_id=district_id,
        #         place=place,
        #         mobile=mobile,
        #         tel=tel,
        #         email=email
        #     )
        # except DatabaseError as e:
        #     logger.error(e)
        #     return http.HttpResponseForbidden('新增收获地址有误')

        address.title = title
        address.receiver = receiver
        address.province_id = province_id
        address.city_id = city_id
        address.district_id = district_id
        address.place = place
        address.mobile = mobile
        address.tel = tel
        address.email = email
        address.save()

        address_dict = {
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province_id': address.province_id,
            'province': address.province.name,
            'city_id': address.city_id,
            'city': address.city.name,
            'district_id': address.district_id,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '修改收货地址成功', 'address': address_dict})

    def delete(self, request, address_id):
        user = request.user
        try:
            address = Address.objects.get(id=address_id, user = user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('address_id有误')
        address.address_id = True
        address.save()

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除收货地址成功'})

class UpdateAddressTitleView(LoginRequiredView):

    def put(self, request, address_id):
        user = request.user
        try:
            address = Address.objects.get(id=address_id, user=user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('address_id有误')

        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        if title is None:
            return http.HttpResponseForbidden('缺少title')

        address.title = title
        address.save()

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '修改地址标题成功'})

class UserDefaultAddressView(LoginRequiredView):

    def put(self, request, address_id):
        user = request.user
        try:
            address = Address.objects.get(id=address_id, user=user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('address_id有误')

        address.default_address = address
        address.save()

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})


class ChangeUserPasswordView(LoginRequiredView):

    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):

        query_dict = request.POST
        old_pwd = query_dict.get('old_pwd')
        new_pwd = query_dict.get('new_pwd')
        new_cpwd = query_dict.get('new_cpwd')

        if all([new_pwd, new_pwd, new_cpwd]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        user = request.user
        if user.check_password(old_pwd) is False:
            return render(request, 'user_center_pass.html', {'origin_pwd_errmsg': '原始密码有误'})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_pwd):
            return http.HttpResponseForbidden('密码最少8位，最长20位')
        if new_pwd != new_cpwd:
            return http.HttpResponseForbidden('两次输入的密码不一致')

        user.set_password(new_pwd)
        user.save()

        # return redirect('/logout/')
        logout(request)
        response = redirect('/login/')
        response.delete_cookie('username')

        return response


class UserBrowseHistory(View):

    def post(self, request):

        user = request.user
        if not user.is_authenticated:
            return http.JsonResponse({'code': RETCODE.SESSIONERR, 'errmsg': '未登陆用户不能添加浏览记录'})
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        try:
            sku_model = SKU.objects.get(id = sku_id, is_launched=True)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku_id不存在')

        redis_conn = get_redis_connection(('history'))

        key = 'history_%s' % user.id

        pl = redis_conn.pipeline()
        pl.lrem(key, 0, sku_id)

        pl.lpush(key, sku_id)
        pl.ltrim(key, 0, 4)
        pl.execute()

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

    def get(self, request):

        user = request.user
        if not user.is_authenticated:
            return http.JsonResponse({'code': RETCODE.SESSIONERR, 'errmsg': '未登陆用户没有商品浏览记录'})

        redis_conn = get_redis_connection('history')

        sku_ids = redis_conn.lrange('history_%s' % user.id, 0, -1)
        # sku_qs = SKU.objects.filter(id__in=[1, 2]) 此种写法浏览记录顺序就乱了
        sku_list = []
        for sku_id in sku_ids:
            sku_model = SKU.objects.get(id=sku_id)
            sku_list.append({
                'id': sku_model.id,
                'default_image_url': sku_model.default_image.url,
                'name': sku_model.name,
                'price': sku_model.price
            })

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': sku_list})


class FindPasswordView(View):
    """忘记密码"""

    def get(self, request):
        return render(request, 'find_password.html')
        # return render(request,'find_password.html',{'image_bytes':image_bytes})


class FindPasswordSecondView(View):
    """第二bu"""
    def get(self, request, account):
        # 获取表单数据
        uuid = request.GET.get('image_code_id')
        image_code = request.GET.get('text')
        # 多账号获取用户
        user = get_user_by_account(account)

        if all([uuid, image_code]) is False:
            return http.HttpResponseForbidden('缺少必要参数!')

        if user is None:
            return http.HttpResponseForbidden('此用户不存在')

        # 创建redis连接对象
        redis_conn = get_redis_connection('verify_codes')

        # 获取redis数据库中当前用户图形验证码

        image_code_server_bytes = redis_conn.get(uuid)

        # 删除已经取出的图形验证码,让它只能被用一次

        redis_conn.delete(uuid)

        # 判断redis中图形验证码过期
        if image_code_server_bytes == None:
            return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '验证码过期'})

        # 将bytes类型转换为字符串类型
        image_code_server = image_code_server_bytes.decode()
        print(image_code_server)
        # 用户填写的和redis中的图形验证码是否一致(注意大小问题)
        if image_code.lower() != image_code_server.lower():
            return http.HttpResponseForbidden('图形验证码错误')
            # return http.JsonResponse({'code': 400, 'errmsg': '验证码错误!'})

        # access_token = get_user_check_token(user.id)
        serializer = Serializer(secret_key=settings.SECRET_KEY, expires_in=3600 * 24)
        data = {'user_id': user.id}

        # 3.加密 decode()
        access_token = serializer.dumps(data).decode()
        #
        # context = {
        #     'mobile': user.mobile,
        #     'access_token': access_token
        # }
        return http.JsonResponse(
            {'code': RETCODE.OK, 'errmsg': 'OK', 'mobile': user.mobile, 'access_token': access_token})


class FindPasswordSMSView(View):
    """发送短信验证码"""
    def get(self, request):

        access_token = request.GET.get('access_token')
        serializer = Serializer(secret_key=settings.SECRET_KEY, expires_in=3600 * 24)

        data = serializer.loads(access_token)
        user_id = data.get('user_id')

        # 校验

        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return http.HttpResponseForbidden('模型不存在')

        if all([user_id]) is False:
            return http.HttpResponseForbidden('缺少必要参数')

        mobile = user.mobile

        # 创建redis连接对象
        redis_conn = get_redis_connection('verify_codes')
        # 来发短信之前先尝试性的去redis中获取此手机号60s内是否发送过短信
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        # 判断是否有发送过的标记
        if send_flag:
            return http.JsonResponse({"code": RETCODE.THROTTLINGERR, 'errmsg': '短信发送频繁'})

        # 随机生成一个6位数字作为短信验证码
        sms_code = '%06d' % randint(0, 99999)
        logging.error(sms_code)
        # 管道技术
        # 创建管道
        pl = redis_conn.pipeline()
        # 将短信验证码存储到redis 以备后期注册时进行验证
        pl.setex('sms_%s' % mobile, 300, sms_code)
        # redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_EXPIRE, sms_code)  # 魔法数字

        # 向redis存储一个标识,标记此手机号60s内已经发过短信
        pl.setex('send_flag_%s' % mobile, 60, 1)
        # redis_conn.setex('send_flag_%s' % mobile, 60, '1')

        # 执行管道
        pl.execute()
        # 利用容联云平台发短信
        # CCP().send_template_sms('接收短信手机号', ['短信验证码', '提示用户短信验证码多久过期单位分钟'], '模板id')
        # CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REST],'1')
        # 响应
        tasks.send_sms_code.delay(mobile, sms_code)
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


class EditPasswordView(View):
    def get(self, request, username):

        # 接收sms_code
        sms_code = request.GET.get('sms_code')

        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            return http.HttpResponseForbidden('模型不存在')

        # 校验
        redis_conn = get_redis_connection('verify_codes')

        # 获取redis中短信验证码
        sms_code_server_byte = redis_conn.get('sms_%s' % user.mobile)
        sms_code_server = sms_code_server_byte.decode()

        # 判断验证码是否正确
        if sms_code_server!= sms_code:
            # return http.JsonResponse({'code':400,'errmsg':'手机验证码错误'})
            return http.HttpResponseForbidden('短信验证码错误')

        serializer = Serializer(secret_key=settings.SECRET_KEY, expires_in=3600 * 24)

        # 2.包装要加密字典数据
        data = {'user_id': user.id}

        # 3.加密 decode()
        access_token = serializer.dumps(data).decode()

        # get_user_check_token()


        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'user_id': user.id,'access_token':access_token})

# @csrf_exempt
class CommitPasswordView(View):
    def post(self,request,user_id):

        # 接收参数
        json_dict = json.loads(request.body.decode())
        password = json_dict.get('password')
        password2 = json_dict.get('password2')
        access_token = json_dict.get('access_token')

        # 校验
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return http.HttpResponseForbidden('user模型不存在')

        # 判断两次密码是否一样

        if password==password2:
            user.set_password(password)
            user.save()

        else:
            return http.JsonResponse({'code':RETCODE.SESSIONERR,'errmsg':'两次密码不一致'})


        response = redirect('/login/')
        return response



